package com.hospital.acctmanage.module.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hospital.acctmanage.module.entity.*;
import com.hospital.acctmanage.module.mapper.*;
import com.hospital.acctmanage.module.service.OutpRcptMasterService;
import com.hospital.api.EcardService;
import com.hospital.common.core.module.controller.vo.RefundBillVo;
import com.hospital.common.core.module.entity.PatientInfo;
import com.hospital.common.core.module.entity.WxPayEntity;
import com.hospital.common.core.result.ReturnResult;
import com.hospital.common.core.utils.DateUtil;
import com.hospital.common.core.utils.PayWayVsHis;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.BindingException;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lvyao
 * @since 2021-09-15
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class OutpRcptMasterServiceImpl extends ServiceImpl<OutpRcptMasterMapper, OutpRcptMaster> implements OutpRcptMasterService {

    @Resource
    private OutpRcptMasterMapper outpRcptMasterMapper;

    @Resource
    private EcardService ecardService;

    @Resource
    private OutpPaymentsMoneyMapper outpPaymentsMoneyMapper;

    @Resource
    private OutpPrepayRcptMapper outpPrepayRcptMapper;


    @Resource
    private OutpPrepayRcptTempMapper outpPrepayRcptTempMapper;


    @Override
    public String getTokenUrl() {
        return outpRcptMasterMapper.getTokenUrl();
    }

    @Override
    public ReturnResult settle(List<WxPayEntity> wxPayEntityList) throws Exception {
        StopWatch stopwatch = new StopWatch();
        stopwatch.start();
        ReturnResult returnResult = new ReturnResult();
        if (wxPayEntityList == null || wxPayEntityList.size() <= 0) {
            returnResult.setMessage("申请中无需要结算的订单！");
            return returnResult;
        }
        for (WxPayEntity wxPayEntity : wxPayEntityList) {
            PatientInfo patientInfo = ecardService.getPatientInfo(wxPayEntity.getPatientId());
            PatMasterIndex patMasterIndex = new PatMasterIndex();
            BeanUtils.copyProperties(patientInfo,patMasterIndex);
            String[] billnoList = wxPayEntity.getBillNo().split(",");
            boolean settle = false;
            String winno = outpRcptMasterMapper.getWinno();
            String maxRcptNo;
            if (wxPayEntity.getRcptNo() == null || wxPayEntity.getRcptNo().equals("")) {
                try {
                    maxRcptNo = String.valueOf(outpRcptMasterMapper.getMaxRcptNo(winno));
                } catch (BindingException b) {
                    maxRcptNo = winno + "000000";
                }
                if (maxRcptNo.equals(winno + "999999")) {
                    returnResult.setMessage(winno + "窗口号的所有收据号已占用完，请重新设置！");
                    return returnResult;
                } else {
                    maxRcptNo = String.valueOf(Integer.parseInt(maxRcptNo) + 1);
                }
            } else {
                maxRcptNo = wxPayEntity.getRcptNo();
            }
            try {
                if (billnoList != null && billnoList.length > 0) {
                    returnResult = settleSpecial(billnoList, wxPayEntity, patMasterIndex, maxRcptNo);
                } else {
                    if (wxPayEntity.getSettleType() == null || wxPayEntity.getSettleType().equals("1")) {
                        returnResult = settleOne(wxPayEntity, patMasterIndex, maxRcptNo);
                    } else if (wxPayEntity.getSettleType().equals("2")) {
                        returnResult = settleDay(wxPayEntity, patMasterIndex, maxRcptNo);
                    } else if (wxPayEntity.getSettleType().equals("3")) {
                        returnResult = settleVisit(wxPayEntity, patMasterIndex, maxRcptNo);
                    } else {
                        returnResult = settleOne(wxPayEntity, patMasterIndex, maxRcptNo);
                    }
                }
            } catch (Exception e) {
                throw e;
            }
            settle = returnResult.isStatus();
            if (!settle) {
                returnResult.setMessage(returnResult.getMessage() + "结算业务失败！");
                return returnResult;
            }
        }
        return returnResult;
    }

    @Override
    public ReturnResult refundSettle(RefundBillVo refundBillVo) throws RuntimeException {
        ReturnResult returnResult = new ReturnResult();
        OutpRcptMaster outpRcptMaster = outpRcptMasterMapper.selectById(refundBillVo.getNumberNo());
        if (outpRcptMaster==null||outpRcptMaster.getChargeIndicator()==2){
            throw new RuntimeException("此结算单已退不能重复退费！");
        }
        List<OutpPaymentsMoney> outpPaymentsMoneyList = outpPaymentsMoneyMapper.selectList(new QueryWrapper<OutpPaymentsMoney>().eq("rcpt_no", refundBillVo.getNumberNo()));
        Timestamp sysdate = outpRcptMasterMapper.getSysdate();
        OutpRcptMaster outpRcptMasterRefund = new OutpRcptMaster();
        BeanUtils.copyProperties(outpRcptMaster, outpRcptMasterRefund);
        outpRcptMasterRefund.setRcptNo(refundBillVo.getRefundRcpt());
        outpRcptMasterRefund.setVisitDate(sysdate);
        BigDecimal zero = new BigDecimal("0");
        BigDecimal totalCharges = zero.subtract(outpRcptMaster.getTotalCharges());
        BigDecimal totalCosts = zero.subtract(outpRcptMaster.getTotalCosts());
        outpRcptMasterRefund.setTotalCharges(totalCharges);
        outpRcptMasterRefund.setTotalCosts(totalCosts);
        outpRcptMasterRefund.setAcctNo("");
        outpRcptMasterRefund.setOperatorNo(refundBillVo.getOperNo());
        outpRcptMasterRefund.setChargeIndicator(2);
        outpRcptMaster.setChargeIndicator(2);
        outpRcptMaster.setRefundedRcptNo(refundBillVo.getRefundRcpt());
        try {
            //退费订单数据处理
            OutpPrepayRcptTemp outpPrepayRcptTemp = outpPrepayRcptTempMapper.selectOne(new QueryWrapper<OutpPrepayRcptTemp>().apply("refunded_rcpt_no = {0}", refundBillVo.getNumberNo()));
            if (outpPrepayRcptTemp != null) {
                outpPrepayRcptTemp.setRcptNo(refundBillVo.getRefundRcpt());
                outpPrepayRcptTemp.setHisTransactDate(DateUtil.format(sysdate));
                outpPrepayRcptTemp.setHisTranStatus("1");
                Integer uddate = outpPrepayRcptTempMapper.updateById(outpPrepayRcptTemp);
                if (uddate < 0) {
                    throw new RuntimeException("更新退费订单失败！");
                }
            }
            //退费结算金额数据处理
            outpPaymentsMoneyList.stream().forEach(outpPaymentsMoney -> {
                BigDecimal paymentAmount = zero.subtract(outpPaymentsMoney.getPaymentAmount());
                BigDecimal refundedAmount = zero.subtract(outpPaymentsMoney.getRefundedAmount());
                outpPaymentsMoney.setPaymentAmount(paymentAmount);
                outpPaymentsMoney.setRefundedAmount(refundedAmount);
                outpPaymentsMoney.setRcptNo(refundBillVo.getRefundRcpt());
                if (outpPaymentsMoney.getMoneyType().equals("预交金")){
                    OutpPrepayRcpt outpPrepayRcpt = new OutpPrepayRcpt();
                    outpPrepayRcpt.setPatientId(outpRcptMaster.getPatientId());
                    outpPrepayRcpt.setRcptNo(outpRcptMasterRefund.getRcptNo());
                    outpPrepayRcpt.setCheckNo(outpRcptMasterRefund.getRcptNo());
                    outpPrepayRcpt.setAmount(outpRcptMaster.getTotalCharges());
                    outpPrepayRcpt.setPayWay("预交金");
                    outpPrepayRcpt.setTransactType("退还");
                    outpPrepayRcpt.setTransactDate(sysdate);
                    outpPrepayRcpt.setOperatorNo(refundBillVo.getOperNo());
                    outpPrepayRcpt.setOutpOrInp("1");
                    Integer insert = outpPrepayRcptMapper.insert(outpPrepayRcpt);
                    if (insert < 0) {
                        throw new RuntimeException("插入退结算付费分类预交金充值记录失败！");
                    }
                }
                Integer insert = outpPaymentsMoneyMapper.insert(outpPaymentsMoney);
                if (insert < 0) {
                    throw new RuntimeException("插入退结算付费分类表数据失败！");
                }
            });

            Integer update = outpRcptMasterMapper.updateById(outpRcptMaster);
            if (update < 0) {
                throw new RuntimeException("更新门诊结算表数据失败！");
            }

             update = outpRcptMasterMapper.insert(outpRcptMasterRefund);
            if (update < 0) {
                throw new RuntimeException("插入退结算结算表数据失败！");
            }
            returnResult.setStatus(true);
        } catch (RuntimeException e) {
            throw new RuntimeException(e.getMessage());
        } catch (Exception e) {
            throw new RuntimeException("退费处理结算信息数据失败！");
        }
        return returnResult;
    }

    public ReturnResult settleSpecial(String[] billnoList, WxPayEntity wxPayEntity, PatMasterIndex patMasterIndex, String maxRcptNo) throws Exception {

//        List<OutpBillItems> outpBillItemsList = outpBillItemsMapper.getOutpBillItems(billnoList);
        ReturnResult returnResult = new ReturnResult();
//        if (outpBillItemsList == null ||  outpBillItemsList.size() <= 0  ) {
//            returnResult.setMessage("根据申请的订单号查询不到计费数据！");
//            return returnResult;
//        }
//        BigDecimal sumCosts = outpBillItemsList.stream().map(OutpBillItems::getCosts).reduce(BigDecimal.ZERO, BigDecimal::add);
//        BigDecimal sumCharges = outpBillItemsList.stream().map(OutpBillItems::getCharges).reduce(BigDecimal.ZERO, BigDecimal::add);
//        BigDecimal wxAmount = new BigDecimal(wxPayEntity.getOrderAmt());
//        if (sumCharges.compareTo(wxAmount) != 0) {
//            returnResult.setMessage("根据申请的订单的总合计与需处理订单合计不相等！");
//            return returnResult;
//        }
        try {
            OutpRcptMaster outpRcptMaster1 = outpRcptMasterMapper.selectById(maxRcptNo);
            String currentRcptNo = outpRcptMaster1 != null ? outpRcptMasterMapper.getSettleNo() : maxRcptNo;

            OutpRcptMaster outpRcptMaster = new OutpRcptMaster();
            outpRcptMaster.setRcptNo(currentRcptNo);
            outpRcptMaster.setVisitDate(DateUtil.format(new Date()));
            BigDecimal payAmount = new BigDecimal(wxPayEntity.getOrderAmt());
            outpRcptMaster.setTotalCosts(payAmount);
            outpRcptMaster.setTotalCharges(payAmount);
            outpRcptMaster.setOperatorNo(wxPayEntity.getOper() == null || wxPayEntity.getOper().equals("") ? "0000" : wxPayEntity.getOper());
            outpRcptMaster.setChargeIndicator(0);
            BeanUtils.copyProperties(patMasterIndex, outpRcptMaster);

            int insert = 0;
            insert = outpRcptMasterMapper.insert(outpRcptMaster);
            if (insert >= 0) {
                int updateRcptnoBillno1 = 0;
                int updateRcptnoBillno = 0;
                if (wxPayEntity.getCreateChannel().equals("2")) {
                    for (String billNoSign : billnoList) {
                        updateRcptnoBillno1 = outpRcptMasterMapper.updateBillRcptnoBillno(maxRcptNo, billNoSign.substring(0, 14), billNoSign.substring(14));
                        if (updateRcptnoBillno1 < 0) {
                            throw new RuntimeException("更新门诊收费明细表数据失败！");
                        }
                        updateRcptnoBillno = outpRcptMasterMapper.updateOrderRcptnoBillno(maxRcptNo, billNoSign.substring(0, 14), billNoSign.substring(14));
                        if (updateRcptnoBillno1 < 0) {
                            throw new RuntimeException("更新门诊医嘱表数据失败！");
                        }
                    }

                }
                if (updateRcptnoBillno1 >= 0 && updateRcptnoBillno >= 0) {
                    int insert1 = 0;
                    List<com.hospital.common.core.module.entity.OutpPaymentsMoney> outpPaymentsMoneyList = wxPayEntity.getPayMoneyList();
                    String moneyType = PayWayVsHis.getPayWayCode(wxPayEntity.getScanType());
                    OutpPrepayRcpt outpPrepayRcpt;
                    if (((wxPayEntity.getScanType() == null || wxPayEntity.getScanType().equals("")) || wxPayEntity.getScanType().equals("MOVEINSUR"))
                            && outpPaymentsMoneyList != null && !outpPaymentsMoneyList.isEmpty()) {
                        for (com.hospital.common.core.module.entity.OutpPaymentsMoney outpPaymentsMoney : outpPaymentsMoneyList) {
                            outpPaymentsMoney.setRcptNo(maxRcptNo);
                            int indexOf = outpPaymentsMoneyList.indexOf(outpPaymentsMoney);
                            outpPaymentsMoney.setPaymentNo(indexOf + 1);
                            outpPaymentsMoney.setTradeNo(wxPayEntity.getTradeNo());
                            com.hospital.acctmanage.module.entity.OutpPaymentsMoney  outpPaymentsMoney1 = new OutpPaymentsMoney();
                            BeanUtils.copyProperties(outpPaymentsMoney,outpPaymentsMoney1);
                            insert1 = outpPaymentsMoneyMapper.insert(outpPaymentsMoney1);
                            if (insert1 < 0) {
                                throw new RuntimeException("插入门诊结算付费分类表数据失败！");
                            }
                            if (outpPaymentsMoney.getMoneyType().equals("预交金")) {
                                outpPrepayRcpt = getOuptpPrepayRcpt(outpRcptMaster, wxPayEntity.getTradeNo(), outpPaymentsMoney.getPaymentAmount());
                                Integer insert2 = outpPrepayRcptMapper.insert(outpPrepayRcpt);
                                if (insert2 < 0) {
                                    throw new RuntimeException("插入门诊负冲预交金数据失败！");
                                }
                            }
                        }
                    } else {
                        if (moneyType.equals("预交金")) {
                            outpPrepayRcpt = getOuptpPrepayRcpt(outpRcptMaster, wxPayEntity.getTradeNo(), payAmount);
                            Integer insert2 = outpPrepayRcptMapper.insert(outpPrepayRcpt);
                            if (insert2 < 0) {
                                throw new RuntimeException("插入门诊负冲预交金数据失败！");
                            }
                        }
                        OutpPaymentsMoney outpPaymentsMoney = new OutpPaymentsMoney();
                        outpPaymentsMoney.setMoneyType(moneyType);
                        outpPaymentsMoney.setRcptNo(maxRcptNo);
                        outpPaymentsMoney.setPaymentNo(1);
                        outpPaymentsMoney.setPaymentAmount(payAmount);
                        outpPaymentsMoney.setTradeNo(wxPayEntity.getTradeNo());
                        outpPaymentsMoney.setRefundedAmount(new BigDecimal(0));
                        insert1 = outpPaymentsMoneyMapper.insert(outpPaymentsMoney);
                    }
                    if (insert1 >= 0) {
                        if (outpRcptMasterMapper.updatePrepaySend(maxRcptNo, wxPayEntity.getOrderNo(), wxPayEntity.getTradeNo(), moneyType, wxPayEntity.getOrderAmt()) <= 0) {
                            returnResult.setStatus(false);
                            throw new RuntimeException("更新结算标识失败！");
                        }
                        returnResult.setStatus(true);
                        return returnResult;
                    } else {
                        throw new RuntimeException("插入门诊结算付费分类表数据失败！");
                    }
                } else {
                    throw new RuntimeException("更新门诊医嘱表数据失败或更新门诊收费明细表数据失败！");
                }
            } else {
                throw new RuntimeException("插入门诊结算主表数据失败！");
            }
        } catch (RuntimeException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public OutpPrepayRcpt getOuptpPrepayRcpt(OutpRcptMaster outpRcptMaster, String tradeNo, BigDecimal payAmount) {
        OutpPrepayRcpt outpPrepayRcpt = new OutpPrepayRcpt();
        outpPrepayRcpt.setOutpOrInp("1");
        outpPrepayRcpt.setPayWay("预交金");
        outpPrepayRcpt.setTransactType("结算");
        outpPrepayRcpt.setRcptNo(outpRcptMaster.getRcptNo());
        outpPrepayRcpt.setCheckNo(outpRcptMaster.getRcptNo());
        outpPrepayRcpt.setTransactDate(outpRcptMaster.getVisitDate());
        outpPrepayRcpt.setOperatorNo(outpRcptMaster.getOperatorNo());
        outpPrepayRcpt.setPatientId(outpRcptMaster.getPatientId());
        BigDecimal zero = new BigDecimal(0);
        outpPrepayRcpt.setAmount(zero.subtract(payAmount));
        outpPrepayRcpt.setTradeNo(tradeNo);
        return outpPrepayRcpt;
    }

    public ReturnResult settleOne(WxPayEntity wxPayEntity, PatMasterIndex patMasterIndex, String maxRcptNo) {
        return null;
    }

    public ReturnResult settleDay(WxPayEntity wxPayEntity, PatMasterIndex patMasterIndex, String maxRcptNo) {
        return null;
    }

    private ReturnResult settleVisit(WxPayEntity wxPayEntity, PatMasterIndex patMasterIndex, String maxRcptNo) {
        return null;
    }
}
